﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Common;
using System.Data;
using System.Collections;
using net.windward.utils.ado;

namespace Kailua.net.windward.utils.ado.SPList.custom
{
    /// <summary>
    /// Vendor for SharePoint list data sources.  This is like a DbProviderFactory.
    /// </summary>
    public class WrSPListVendor2 : WrVendor
    {
        #region Fields
        /// <summary>
        /// The DbProviderFactory class, "net.windward.utils.ado.SPList.custom.SPListProviderFactory".
        /// </summary>
        public const string FactoryClass = "net.windward.utils.ado.SPList.custom.SPListProviderFactory";
        /// <summary>
        /// The display name, "SharePoint List".
        /// </summary>
        public const string FactoryDispName = "SharePoint List";
        /// <summary>
        /// "SPList"
        /// </summary>
        public const string PROVIDER_SUBTYPE = "SPList";
        #endregion Fields

        #region Constructors
        /// <summary>
        /// Creates an SharePoint list vendor object.
        /// </summary>
        public WrSPListVendor2()
            : base(FactoryDispName, "SharePoint list connector", FactoryClass)
        {
            syntax = new WrSPListSyntax2();
            loadSPListProviderFactory();
        }
        /// <summary>
        /// Creates an SharePoint list vendor object.
        /// </summary>
        /// <param name="name">The friendly name of the provider.</param>
        /// <param name="description">The description of this provider (optional).</param>
        /// <param name="providerClass">The class of the provider.</param>
        public WrSPListVendor2(string name, string description, string providerClass)
            : base(name, description)
        {
            syntax = new WrSPListSyntax2();
            loadSPListProviderFactory();
        }
        /// <summary>
        /// Loads the splist provider factory. The splist provider factory cannot be loaded by a DbProviderFactories.GetFactory(string invariantName) 
        /// call, because it is not registered that way, so we load it manually after the default constructor has run.
        /// </summary>
        private void loadSPListProviderFactory()
        {
            try
            {
                providerFactory = GetSPListDbProviderFactory();
            }
            catch (Exception ex)
            {
                providerFactory = null;
            }
        }
        #endregion Constructors

        #region Properties
        /// <summary>
        /// Returns false. WrSPListVendor cannot enumerate servers.
        /// </summary>
        public override bool CanEnumerateServers
        {
            //bugbug: verify if site collections can be enumerated; verify if web apps can be enumerated
            get { return false; }
        }
        /// <summary>
        /// Returns true.  In this case, databases are SharePoint websites (SPWeb).
        /// </summary>
        public override bool CanEnumerateDatabases
        {
            get { return true; }
        }
        #endregion Properties

        #region WrVendor
        /// <summary>
        /// Returns false.  WrSPListVendor has no administrator program file.
        /// </summary>
        public override bool CanLaunchAdministrator
        {
            //bugbug: dave, what is this prop for?  what is an administrator program?
            get { return false; }
        }
        /// <summary>
        /// Returns false.  WrSPListVendor is readonly and cannot run DDL scripts.
        /// </summary>
        public override bool CanRunScripts
        {
            get { return false; }
        }
        /// <summary>
        /// Returns false.  WrSPListVendor cannot use Windows authentication.
        /// </summary>
        public override bool CanUseTrustedConnection
        {
            //bugbug: verify whether list service can use windows authentication
            get { return false; }
        }
        /// <summary>
        /// Creates a connection string from the specified values.
        /// </summary>
        /// <param name="server">This is the server field in autotag. It should contain the URL to an SPWeb.</param>
        /// <param name="database">This is the database field in autotag. It should be empty or contain a "ListName,{GUID}" string.</param>
        /// <param name="credentials"></param>
        /// <param name="showPassword">If true, the password will be placed in the connection string; else, "****" will appear.</param>
        /// <returns></returns>
        public override string ConnectionString(string server, string database, WrCredentials credentials, bool showPassword)
        {
            return CreateConnStr(server, database, credentials, showPassword);
        }
        /// <summary>
        /// Creates a connection string from the specified values.
        /// </summary>
        /// <param name="server">This is the server field in autotag. It should contain the URL to an SPWeb.</param>
        /// <param name="database">This is the database field in autotag. It should be empty or contain a "ListName,{GUID}" string.</param>
        /// <param name="credentials"></param>
        /// <param name="showPassword">If true, the password will be placed in the connection string; else, "****" will appear.</param>
        /// <returns></returns>
        internal static string CreateConnStr(string server, string database, WrCredentials credentials, bool showPassword)
        {
            if (string.IsNullOrEmpty(server))
                return string.Empty;

            // server is an SPWeb URL
            string spWebUrl = server;
            // database is a ListName,{GUID} string
            string listSpec = database;

            // get the list ID
            int pos = listSpec.LastIndexOf(',');
            string listGuid = listSpec.Substring(pos + 1);

            // assemble the connection string
            StringBuilder connStrBldr = new StringBuilder();
            connStrBldr.AppendFormat("URL={0};", spWebUrl);
            if (!string.IsNullOrEmpty(listGuid))
                connStrBldr.AppendFormat("LIST={0};", listGuid);
            if (!string.IsNullOrEmpty(credentials.Domain))
                connStrBldr.AppendFormat("DOMAIN={0};", credentials.Domain);
            if (!string.IsNullOrEmpty(credentials.Username))
                connStrBldr.AppendFormat("USER={0};", credentials.Username);
            if (!string.IsNullOrEmpty(credentials.Password))
            {
                if (showPassword)
                    connStrBldr.AppendFormat("PASSWORD={0};", credentials.Password);
                else
                    connStrBldr.AppendFormat("PASSWORD=****;", credentials.Password);
            }

            return connStrBldr.ToString();
        }
        /// <summary>
        /// Creates WrConnectionParams from the specified connection string.
        /// </summary>
        /// <param name="connectionString"></param>
        /// <returns></returns>
        public override WrConnectionParams ConnectionParams(string connectionString)
        {
            // here, we need to parse the connection string into server, database, username, password, etc.
            // we may need a special connection params or we may need to adjust kailua beyond this

            // parse the connection string
            Hashtable keyPairs = SPListConnection.ParseConnectionString(connectionString);
            WrSPListConnectionParams connParams = new WrSPListConnectionParams();
            string spWebUrl = (string)keyPairs["URL"];
            string listGuid = null;
            if (keyPairs.ContainsKey("LIST"))
                listGuid = (string)keyPairs["LIST"];
            string user = null;
            string password = null;
            if (keyPairs.ContainsKey("USER"))
                user = (string)keyPairs["USER"];
            if (keyPairs.ContainsKey("PASSWORD"))
                password = (string)keyPairs["PASSWORD"];

            // return the connection params
            if (user != null && password != null)
                return new WrSPListConnectionParams(spWebUrl, listGuid, user, password);
            return new WrSPListConnectionParams();
        }
        /// <summary>
        /// Creates a new WrSPListCommand.
        /// </summary>
        /// <returns></returns>
        public override WrCommand CreateCommand()
        {
            return new WrSPListCommand2(providerFactory);
        }
        /// <summary>
        /// Creates a new WrSPListServer from the specified URL.
        /// </summary>
        /// <param name="url">The URL of the SPWeb. For sql databases, this would instead be server name.</param>
        /// <returns></returns>
        public override IWrServer CreateServer(string url)
        {
            return new WrSPListServer2(url);
        }
        /// <summary>
        /// Gets the WrVendor.DATABASE_MODE.
        /// </summary>
        public override WrVendor.DATABASE_MODE DatabaseMode
        {
            get
            {
                return WrVendor.DATABASE_MODE.NEVER;
            }
        }
        /// <summary>
        /// Indicates if the WrSPListVendor is installed.
        /// </summary>
		public override bool IsInstalled
        {
            get
            {
                // the splist provider is built into Kailua
                return true;

                #region old DbProviderFactories discover code
                // this block was when we were using DbProviderFactories discover code
                /*
                try
                {
                    DbProviderFactory providerFactory = GetSPListDbProviderFactory();
                    return true;
                }
                catch
                {
                    return false;
                }
                */
                #endregion old DbProviderFactories discover code
            }
        }
        /// <summary>
        /// Gets Windward's SPList DbProviderFactory.  If the factory is not found, this will throw an exception.
        /// </summary>
        /// <returns></returns>
        private static DbProviderFactory GetSPListDbProviderFactory()
        {
            // this block was when we were using DbProviderFactories to discover the provider
            /*
            DataTable table = new DataTable();
            table.Columns.Add(new DataColumn("Name", typeof(string)));
            table.Columns.Add(new DataColumn("Description", typeof(string)));
            table.Columns.Add(new DataColumn("InvariantName", typeof(string)));
            table.Columns.Add(new DataColumn("AssemblyQualifiedName", typeof(string)));
            DataRow providerRow = table.NewRow();
            providerRow["Name"] = "SharePoint List";
            providerRow["InvariantName"] = "WindwardArrow.SPList";
            providerRow["Description"] = "Windward's SharePoint List Data Provider";
            providerRow["AssemblyQualifiedName"] = "SPListProviderFactory.SPListProviderFactory, Windward.Data, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d168e9d1c29e68a7";
            DbProviderFactory providerFactory = DbProviderFactories.GetFactory(providerRow);
            return providerFactory;
            */

            return new SPListProviderFactory();
        }
        /// <summary>
        /// The provider factory subtype. Same as <see cref="WrSPListVendor2.PROVIDER_SUBTYPE"/>, "SPList".
        /// </summary>
        public override string ProviderSubtype
        {
            get
            {
                return PROVIDER_SUBTYPE;
            }
        }
        #endregion WrVendor
    }
}
